﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.IO;
using System.IO.Ports;
using System.Text;
using System.Windows.Forms;
using MetroFramework;
using MetroFramework.Forms;

namespace OfflineProgramer
{
    public partial class Form1 : MetroForm
    {

        List<byte> BinByteSource = new List<byte>(); //BIN 文件暂存变量
                                                     // 配置文件信息
        private List<ProgramFileOperation> programFileOperationList = new List<ProgramFileOperation>();

        // 下拉列表初始化数据信息
        ProgramSettingData programSettingData = new ProgramSettingData();

        ProgramUploadDataOpt uploadDataOpt = new ProgramUploadDataOpt();

        UInt32 fileSendTimes = 0; //需要通讯次数，用来计算进度条

        // 是否连接到烧录器
        bool isConnect = false;

        // 根据字典信息初始化下拉列表
        void InitComboxByDic(ComboBox cmb, object dic)
        {
            if (cmb.DataSource != null) cmb.DataSource = null;
            cmb.Items.Clear();
            cmb.DataSource = new BindingSource(dic, null);
            cmb.ValueMember = "Key";//文本对应的值
            cmb.DisplayMember = "Value";//显示的文本  
        }
        // 根据起始地址,文件长度 计算下一个文件应存储的位置  4k计算
        void SetttingFlashFileAddr(ref ProgramFileOperation opt, UInt32 startAddr)
        {
            opt.FileAddr = startAddr;

            opt.FileAddrNext = startAddr + ((opt.FileLen / 4096) + 1) * 4096;
        }

        // 根据配置信息生成  烧录类型,芯片信息，地址信息,Flash存放位置计算
        void SettingFlashOptInfo(ref ProgramFileOperation opt)
        {
            opt.FlashOpType = (byte)(Convert.ToByte(1));  //1 烧录IC
            opt.ManufactorId = (byte)(Convert.ToByte(cmbManufacturer.SelectedIndex + 1));
            opt.ChipIDCODE = (byte)(Convert.ToByte(cmbType.SelectedIndex + 1));

        }

        // 根据配置信息生成   flash_opt_bit 烧录操作设置 及 烧录次数

        /*
        uint8_t erase         : 1;  // 擦除
        uint8_t check         : 1;  // 校验
        uint8_t speed         : 1;  // 烧录速度
        uint8_t isAuto        : 1;  // 是否自动烧录
        uint8_t isReset       : 1;  // 是否自动重启
        uint8_t voltage       : 1;  // 输出电压选择
        uint8_t protect       : 1;  // 读写保护
        uint8_t burnTimes     : 1;  // 关闭开启烧录次数
        */


        void SettingFlashOptBit(ref ProgramFileOperation opt)
        {
            opt.Flash_opt_bit = 0;
            if(rbEraseSector.Checked)
            opt.Flash_opt_bit |= 1;

            if (!chkCheck.Checked)
            {
                opt.Flash_opt_bit |= 1 << 1;
            }
   
            opt.Flash_opt_bit |= (byte)(Convert.ToByte(0) << 2);

            //if (chkAutoProg.Checked) opt.Flash_opt_bit |= 1 << 3;

            if (chkRestart.Checked) opt.Flash_opt_bit |= 1 << 4;

            if(rbPower5V.Checked) opt.Flash_opt_bit |= 1 << 5;

            // if (chkReadProtect.Checked) opt.Flash_opt_bit |= 1 << 6;

            // if (chkBurnTimes.Checked) opt.Flash_opt_bit |= 1 << 7;
            
            opt.BurnTimes = 0;
            opt.FlashAddr = 0;

            string hexString = "";

            hexString = txtFlashAddr.Text;

            hexString = hexString.Remove(0, 2);
            try
            {
                opt.FlashAddr = UInt32.Parse(hexString, System.Globalization.NumberStyles.HexNumber);
            }
            catch
            { }
            

        }
        public Form1()
        {
            InitializeComponent();
        }

        // SerialPort serialPort = new SerialPort();
        private void HexDis(byte[] by)
        {
           // System.Console.Write("TX :");

            for (int i = 0; i < by.Length; i++)
            {
                System.Console.Write(" "); ;
                System.Console.Write(by[i].ToString("X2"));

            }
            System.Console.WriteLine();

        }
        SerialPort m_SerialPort;
        string[] m_PortList;
        private void Form1_Load(object sender, EventArgs e)
        {
            InitComboxByDic(cmbManufacturer, programSettingData.dicManufactorId_IC);

            cmbManufacturer.SelectedIndex = 0;
            cmbType.SelectedIndex = 0;

            rbEraseFull.Checked = true;
            rbPower3V3.Checked = true;

            // 获取串口列表
            m_PortList = SerialPort.GetPortNames();

            // 更新到cmb中
            cmbSerialName.Items.AddRange(m_PortList);
            cmbSerialName.SelectedIndex = 0;

            // serialPort.PortName = "COM5";

            ProgramFrame.FrameCmdRecvDada += ProgramFrame_FrameCmdRecvDada;
          //  serialPort.Open()
        }

        private void btnSerialSet()
        {
            this.Invoke(new Action(() =>
            {
                try
                {

                    btnSerialOpen.Text = "关闭串口";
                    btnSerialOpen.ForeColor = Color.Green;

                }
                catch
                { };
            }));

        }

        private void SetProcess(int value)
        {
            this.Invoke(new Action(() =>
            {
                try
                {
                    pbProcess.Value = value;
                }
                catch
                { };
            }));

        }
        // 解析好的数据
        private void ProgramFrame_FrameCmdRecvDada(byte[] cmdFrame)
        {
            System.Console.Write("Rx :");
            HexDis(cmdFrame);
            switch ((ProgramFrame.PRO_FRAM_CMD)cmdFrame[3])
            {
                case ProgramFrame.PRO_FRAM_CMD.SETTING_SLAVE_ADDR_ANS:

                    // 连接到烧录器
                    isConnect = true;

                    btnSerialSet();

                    break;
                case ProgramFrame.PRO_FRAM_CMD.QUERY_SLAVE_STATE_ANS:
                    break;
                case ProgramFrame.PRO_FRAM_CMD.SEND_OPT_CMD_ANS:
                    break;
                case ProgramFrame.PRO_FRAM_CMD.TRANS_DATA_STRUCT_CMD_ANS:
                    uploadDataOpt.cureStructId++;
                    GetSendBinData();

                    break;
                case ProgramFrame.PRO_FRAM_CMD.TRANS_DATA_CMD_ANS:
                    if (fileSendTimes != 0)   SetProcess((int)((float)((float)uploadDataOpt.cureBinSendDataId / (float)fileSendTimes) * 100));

                    UInt32 dataorder = 0;
                    dataorder |= (UInt32)(cmdFrame[9] << 24);
                    dataorder |= (UInt32)cmdFrame[10] << 16;
                    dataorder |= (UInt32)cmdFrame[11] << 8;
                    dataorder |= cmdFrame[12];
                    System.Console.WriteLine(string.Format("应答数据文件ID:{0} 数据序号{1} 数据长度:{2}:\r\n", cmdFrame[8], dataorder, cmdFrame[13]));
                   // textInfo.Text += string.Format("应答数据文件ID:{0} 数据序号{1} 数据长度:{2}:\r\n", cmdFrame[8], dataorder, cmdFrame[13]);
                    uploadDataOpt.cureBinSendDataId++;
                    GetSendBinData();

                    break;
                case ProgramFrame.PRO_FRAM_CMD.TRANS_DATA_FINISH_CMD_ANS:
                    break;
                    // throw new NotImplementedException();
            }
        }

        private void SetFileInfo(string fileName, int fileLength, int crc8)
        {
            this.Invoke(new Action(() =>
            {
                try
                {
                    labFileName.Text = fileName;
                    labFileLength.Text = Math.Round((fileLength / 1024.0f), 2).ToString() + "Kb";
                    labFileCRC.Text = "0x" + crc8.ToString("X2");
                }
                catch
                { };
            }));

        }

        private void btnOpenFile_Click(object sender, EventArgs e)
        {
            UInt32 fileLength = 0;
            UInt32 fileCrc = 0;
            string fileName = "";
            OpenFileDialog ofd = new OpenFileDialog();
            ofd.Filter = "Bin文件(*.bin)|*.bin|所有文件(*.*)|*.*"; //设置“另存为文件类型”或“文件类型”框中出现的选择内容
            ofd.FilterIndex = 1;
            ofd.Title = "打开文件";
            BinByteSource.Clear();

            if (ofd.ShowDialog() == DialogResult.OK)
            {
                //FileName：所选文件的全路径  SafeFileName：所选的文件名
                fileName = ofd.SafeFileName;
                FileStream fsRead = new FileStream(ofd.FileName, FileMode.Open, FileAccess.Read);
                byte[] buffer = new byte[1024];//声明一个字节数组，用来临时存储读取到数据，最大存储200字节
                fileLength = (UInt32)fsRead.Length;
                while (true)
                {
                    Array.Clear(buffer, 0, buffer.Length);
                    int r = fsRead.Read(buffer, 0, buffer.Length);//返回本次实际读取到的字节数 
                    if (r == 0)//如果读取到的字节数为0，说明已到达文件结尾，则退出while循环
                    {
                        break;
                    }
                    BinByteSource.AddRange(buffer);
                }
                fsRead.Close();  //关闭流
                fsRead.Dispose(); //释放流


                ProgramFileOperation programFileOperation = new ProgramFileOperation();
                programFileOperation.FileBinData = new byte[fileLength];
                Buffer.BlockCopy(BinByteSource.ToArray(), 0, programFileOperation.FileBinData, 0, (int)fileLength);
                programFileOperation.FileBinData = BinByteSource.ToArray();
                programFileOperation.FileCrc = Hash.CRC32(0, programFileOperation.FileBinData, fileLength);
                programFileOperation.FileLen = fileLength;
                programFileOperation.FileNameStr = System.Text.Encoding.ASCII.GetBytes(fileName);

                SetFileInfo(fileName, (int)fileLength, (int)programFileOperation.FileCrc);
                // 加入到DGView
                // AddBinFileInfoToDgView(0, fileName, programFileOperation.FlashAddr, 0, programFileOperation.FileLen / 1024, programFileOperation.FileCrc);

                SettingFlashOptInfo(ref programFileOperation);
                SettingFlashOptBit(ref programFileOperation);

                programFileOperationList.Clear();

                SetttingFlashFileAddr(ref programFileOperation, 0);

                programFileOperationList.Add(programFileOperation);
                uploadDataOpt.fileNum = 1;  //要发送的文件数量

                fileSendTimes = fileLength / uploadDataOpt.SEND_BIN_FILE_LEN + 1;

            }

        }

        public byte GetSendBinData()
        {

            if (ProgramUploadDataOpt.UPLOAD_STATE.START_SEND_STRUCT == uploadDataOpt.upState)  //发送结构
            {

                int curStructId = uploadDataOpt.cureStructId;
                if (curStructId < uploadDataOpt.fileNum)
                {
                    byte[] data = programFileOperationList[curStructId].GetPackDataToByte();
                    ProgramFrame.Pack_TransDataStructCMD(uploadDataOpt.sendOrder, (byte)curStructId, data);

                    HexDis(ProgramFrame.sendMsgBuf);
                    m_SerialPort.Write(ProgramFrame.sendMsgBuf, 0, ProgramFrame.sendMsgBuf.Length);
                }
                else
                {
                    uploadDataOpt.upState = ProgramUploadDataOpt.UPLOAD_STATE.START_SEND_DATA;
                    uploadDataOpt.cureBinId = 0;

                }


            }

            if (ProgramUploadDataOpt.UPLOAD_STATE.START_SEND_DATA == uploadDataOpt.upState) //发送bin
            {
                // 计算要发送的内容并且发送
                int curDataId = 0;
                int dataSendLen = 0;

                /*
                if ((programFileOperationList[uploadDataOpt.cureBinId].FileBinData.Length - uploadDataOpt.cureBinSendDataId  * uploadDataOpt.SEND_BIN_FILE_LEN)<= 0) //已经发送完毕，需要发送下一个文件
                {
                    uploadDataOpt.cureBinId++;
                }
                */

                curDataId = uploadDataOpt.cureBinId;

                if (curDataId < uploadDataOpt.fileNum)
                {
                    // 计算要发送的内容
                    // bin文件大小
                    int dataBinLen = programFileOperationList[curDataId].FileBinData.Length;
                    int dataStartCopyAddr = 0;  // bin 复制位置的起始位置
                    // 要发送的字节
                    byte[] sendDataByte = new byte[uploadDataOpt.SEND_BIN_FILE_LEN];
                    dataStartCopyAddr = (int)uploadDataOpt.cureBinSendDataId * (int)uploadDataOpt.SEND_BIN_FILE_LEN;
                    if ((uploadDataOpt.cureBinSendDataId + 1) * uploadDataOpt.SEND_BIN_FILE_LEN <= dataBinLen)
                    {
                        dataSendLen = uploadDataOpt.SEND_BIN_FILE_LEN;

                    }
                    else
                    {
                        dataSendLen = dataBinLen - ((int)uploadDataOpt.cureBinSendDataId * (int)uploadDataOpt.SEND_BIN_FILE_LEN);

                    }

                    // 有可以发送的数据发送
                    if (dataSendLen > 0)
                    {
                        Buffer.BlockCopy(programFileOperationList[curDataId].FileBinData, dataStartCopyAddr, sendDataByte, 0, dataSendLen);
                        ProgramFrame.Pack_TransDataCMD(uploadDataOpt.sendOrder, (byte)curDataId, uploadDataOpt.cureBinSendDataId, (byte)dataSendLen, sendDataByte);

                        HexDis(ProgramFrame.sendMsgBuf);
                        m_SerialPort.Write(ProgramFrame.sendMsgBuf, 0, ProgramFrame.sendMsgBuf.Length);
                        // uploadDataOpt.cureBinSendDataId++;
                    }
                    else  // 发送下一个文件
                    {
                        uploadDataOpt.cureBinId++;
                        uploadDataOpt.cureBinSendDataId = 0;
                        GetSendBinData();
                    }

                }
                else
                {
                    // 发送文件发送完成
                }


            }

            return 0;
        }

        private void btnDownLoad_Click(object sender, EventArgs e)
        {
            if (m_SerialPort == null || isConnect == false )
            {
                MessageBox.Show("请先打开串口，连接烧录器");
                return;
            }

            if (uploadDataOpt.fileNum != 1)
            {
                MessageBox.Show("请先打开要上传的文件");
                return;
            }
            uploadDataOpt.upState = ProgramUploadDataOpt.UPLOAD_STATE.START_SEND_STRUCT;
            uploadDataOpt.cureBinId = 0;
            uploadDataOpt.cureStructId = 0;

            GetSendBinData();
        }

        private void cmbManufacturer_SelectedIndexChanged(object sender, EventArgs e)
        {
            try
            {
                InitComboxByDic(cmbType, programSettingData.chipIdCodeList_IC[cmbManufacturer.SelectedIndex]);

            }
            catch (Exception ee)
            { }
        }

        private void rbEraseSector_CheckedChanged(object sender, EventArgs e)
        {
           
        }

        private void rbEraseFull_CheckedChanged(object sender, EventArgs e)
        {
           
        }

        private void rbPower3V3_CheckedChanged(object sender, EventArgs e)
        {
          
        }

        private void rbPower5V_CheckedChanged(object sender, EventArgs e)
        {
          
        }

        private void rbEraseSector_Click(object sender, EventArgs e)
        {
            rbEraseSector.Checked = true;
            rbEraseFull.Checked = false;
        }

        private void rbEraseFull_Click(object sender, EventArgs e)
        {
            rbEraseSector.Checked = false;
            rbEraseFull.Checked = true;
        }

        private void rbPower3V3_Click(object sender, EventArgs e)
        {
            rbPower3V3.Checked = true;
            rbPower5V.Checked = false;
        }

        private void rbPower5V_Click(object sender, EventArgs e)
        {
            rbPower3V3.Checked = false;
            rbPower5V.Checked = true;
        }

        private void btnSerialOpen_Click(object sender, EventArgs e)
        {
            if (isConnect)
            {
                if (m_SerialPort.IsOpen)
                {
                    m_SerialPort.Close();
                    btnSerialOpen.Text = "打开串口";
                    isConnect = false;
                }
                return;            
            }
            isConnect = false;

            try
            {
                string PortName = cmbSerialName.Items[cmbSerialName.SelectedIndex].ToString();
                if (m_SerialPort == null)
                {
                    m_SerialPort = new SerialPort(PortName, 115200);
                }
                else
                {
                    if (m_SerialPort.IsOpen)
                    {
                        m_SerialPort.Close();
                    }
                    m_SerialPort.PortName = PortName;
                    m_SerialPort.BaudRate = 115200;
                }
                m_SerialPort.Open();
                m_SerialPort.DataReceived += M_SerialPort_DataReceived;

                ProgramFrame.Pack_SettingSlaveAddrCMD(0);
                HexDis(ProgramFrame.sendMsgBuf);
                m_SerialPort.Write(ProgramFrame.sendMsgBuf, 0, ProgramFrame.sendMsgBuf.Length);

            }
            catch
            { 
            
            }
        }

        private void M_SerialPort_DataReceived(object sender, SerialDataReceivedEventArgs e)
        {
            byte[] m_recvBytes = new byte[m_SerialPort.BytesToRead]; //定义缓冲区大小  
            int result = m_SerialPort.Read(m_recvBytes, 0, m_recvBytes.Length); //从串口读取数据  
            if (result <= 0)
                return;

           // string strResult = Encoding.UTF8.GetString(m_recvBytes, 0, m_recvBytes.Length); //对数据进行转换  
            m_SerialPort.DiscardInBuffer();


            ProgramFrame.RxDataReadIntoList(m_recvBytes);
            //throw new NotImplementedException();
        }

        private void metroLabel7_Click(object sender, EventArgs e)
        {
            Form2 form2 = new Form2();
            form2.Show();
        }

        private void cmbType_SelectedIndexChanged(object sender, EventArgs e)
        {

        }
    }
}
